#include "nodeworldobject.h"

namespace gunsmith
{
CNodeWorldObject::CNodeWorldObject(ENODETYPE eType) : CNode(eType)
{
	m_bCollideable	= false;
	m_vDirection	= D3DXVECTOR3(0, 0, 0);
	m_vPosition		= D3DXVECTOR3(0, 0, 0);
	m_vRotation		= D3DXVECTOR3(0, 0, 0);
	m_vScale		= D3DXVECTOR3(1, 1, 1);


	D3DXMatrixIdentity(&m_matLocalTransformation);
	m_matWorldTransformation = m_matLocalTransformation;

	UpdateLocalTransformationMatrix();
	UpdateWorldTransformationMatrix();
}

CNodeWorldObject::~CNodeWorldObject()
{

}

/*!	\brief		Returns the world transformation matrix.
	\return		const D3DXMATRIX* Pointer to the world transformation matrix.
	\remarks	
	\sa			*/
const D3DXMATRIX* CNodeWorldObject::GetWorldTransformationMatrix() const
{
	return &m_matWorldTransformation;
}

/*!	\brief		Returns the local transformation matrix.
	\return		const D3DXMATRIX* Pointer to the local transformation matrix.
	\remarks	
	\sa			*/
const D3DXMATRIX* CNodeWorldObject::GetLocalTransformationMatrix() const
{
	return &m_matLocalTransformation;
}

/*!	\brief		Sets the velocity direction.
	\param		vDirection	Direction vector.
	\return		void
	\remarks	
	\sa			*/
void CNodeWorldObject::SetDirection(const D3DXVECTOR3& vDirection)
{
	m_vDirection = vDirection;
}

/*!	\brief		Sets the position and updates local and world matrix.
	\param		vPosition	Position vector.
	\return		void
	\remarks	
	\sa			*/
void CNodeWorldObject::SetPosition(const D3DXVECTOR3& vPosition)
{
	m_vPosition = vPosition;
	UpdateLocalTransformationMatrix();
	UpdateWorldTransformationMatrix();
}

/*!	\brief		Sets the rotation and updates local and world matrix.
	\param		vRotation	Rotation vector.
	\return		void
	\remarks	
	\sa			*/
void CNodeWorldObject::SetRotation(const D3DXVECTOR3& vRotation)
{
	m_vRotation = vRotation;
	UpdateLocalTransformationMatrix();
	UpdateWorldTransformationMatrix();
}

/*!	\brief		Sets the scale and updates local and world matrix.
	\param		vScale	Scale vector.
	\return		void
	\remarks	
	\sa			*/
void CNodeWorldObject::SetScale(const D3DXVECTOR3& vScale)
{
	m_vScale = vScale;
	UpdateLocalTransformationMatrix();
	UpdateWorldTransformationMatrix();
}

/*!	\brief		Updates the geometry according to the delta time and data provided. (see remarks)
	\param		fDelta	Delta time.
	\param		pData	Additional data.
	\return		void
	\remarks	See CNode.
	\sa			*/
void CNodeWorldObject::Update(float fDelta, void *pData)
{
	SetPosition(m_vPosition + (m_vDirection * fDelta));
}

/*!	\brief		Updates the local transformation matrix.
	\return		void
	\remarks	
	\sa			*/
void CNodeWorldObject::UpdateLocalTransformationMatrix()
{
	D3DXQUATERNION qRotation;
	D3DXQuaternionRotationYawPitchRoll(&qRotation, m_vRotation.y, m_vRotation.x, m_vRotation.z);
	D3DXMatrixTransformation(&m_matLocalTransformation, NULL, NULL, &m_vScale, NULL, &qRotation, &m_vPosition);
}


/*!	\brief		Updates the world transformation matrix. (see remarks)
	\return		void
	\remarks	Uses parent world matrix + own local matrix to receive own world matrix. Also invokes UpdateChildrenWorldMatrices().
	\sa			*/
void CNodeWorldObject::UpdateWorldTransformationMatrix()
{
	CNodeWorldObject *pParentGeometry = dynamic_cast<CNodeWorldObject*>(m_pParent);				// check if parent is world object and has transformation information

	if(pParentGeometry)
	{
		D3DXMatrixMultiply(&m_matWorldTransformation, &m_matLocalTransformation, &pParentGeometry->m_matWorldTransformation);
		UpdateChildrenWorldMatrices(m_pFirstChild);
	}
	else
		m_matWorldTransformation = m_matLocalTransformation;
}

/*!	\brief		Updates all children matrices. (see remarks)
	\param		pNode
	\return		void
	\remarks	Invokes UpdateWorldTransformationMatrix() on sibbling CGeometry notes.
	\sa			*/
void CNodeWorldObject::UpdateChildrenWorldMatrices(CNode *pNode)
{
	if(pNode == NULL)
		return;

	while(pNode)
	{
		CNodeWorldObject *pGeometry = dynamic_cast<CNodeWorldObject*>(pNode);

		if(pGeometry)
			pGeometry->UpdateWorldTransformationMatrix();

		pNode = pNode->GetNextSibbling();
	}
}

/*!	\brief		Returns direction vector.
	\return		const D3DXVECTOR3& Direction vector.
	\remarks	
	\sa			*/
const D3DXVECTOR3& CNodeWorldObject::GetDirection() const
{
	return m_vDirection;
}

/*!	\brief		Returns position vector.
	\return		const D3DXVECTOR3& Position vector.
	\remarks	
	\sa			*/
const D3DXVECTOR3& CNodeWorldObject::GetPosition() const
{
	return m_vPosition;
}

/*!	\brief		Returns rotation vector.
	\return		const D3DXVECTOR3& Rotation vector.
	\remarks	
	\sa			*/
const D3DXVECTOR3& CNodeWorldObject::GetRotation() const
{
	return m_vRotation;
}

/*!	\brief		Returns scale vector.
	\return		const D3DXVECTOR3& Scale vector.
	\remarks	
	\sa			*/
const D3DXVECTOR3& CNodeWorldObject::GetScale() const
{
	return m_vScale;
}
};